package org.dromara.system.controller.system;

import cn.dev33.satoken.annotation.SaCheckPermission;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.domain.R;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.web.core.BaseController;
import org.dromara.system.domain.bo.SysConfigBo;
import org.dromara.system.domain.vo.SysConfigVo;
import org.dromara.system.service.ISysConfigService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.List;


/**
 * @Author 刘武贵
 * @Date 2024/8/15 22:00
 * @Description 功能描述：参数配置 信息操作处理
 */
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/system/config")
public class SysConfigController extends BaseController {

    /**
     * 参数配置 服务层
     */
    private final ISysConfigService configService;

    /**
     * 获取参数配置列表
     *
     * @param config 查询条件，封装了系统配置的查询参数
     * @param pageQuery 分页查询对象，包含了分页的相关信息，如当前页码、每页记录数等
     * @return 返回一个TableDataInfo对象，其中包含了SysConfigVo类型的分页数据列表，
     *         以及总记录数等分页信息
     */
    @SaCheckPermission("system:config:list")
    @GetMapping("/list")
    public TableDataInfo<SysConfigVo> list(SysConfigBo config, PageQuery pageQuery) {
        return configService.selectPageConfigList(config, pageQuery);
    }

    /**
     * 导出参数配置列表
     *
     * @param config 系统配置参数对象，用于过滤和选择要导出的配置项
     * @param response HTTP响应对象，用于将导出的Excel文件返回给客户端
     */
    @Log(title = "参数管理", businessType = BusinessType.EXPORT)
    @SaCheckPermission("system:config:export")
    @PostMapping("/export")
    public void export(SysConfigBo config, HttpServletResponse response) {
        List<SysConfigVo> list = configService.selectConfigList(config);
        ExcelUtil.exportExcel(list, "参数数据", SysConfigVo.class, response);
    }

    /**
     * 根据参数编号获取详细信息
     *
     * @param configId 参数ID
     * @return 返回一个响应对象，其中包含配置信息（SysConfigVo类型）
     */
    @SaCheckPermission("system:config:query")
    @GetMapping(value = "/{configId}")
    public R<SysConfigVo> getInfo(@PathVariable Long configId) {
        return R.ok(configService.selectConfigById(configId));
    }

    /**
     * 根据参数键名查询参数值
     * 该方法用于向系统中添加新的配置参数 在添加参数之前，会先校验参数的合法性以及参数键名的唯一性
     * 如果参数键名已存在，则返回失败的结果，否则调用服务层的方法将参数插入数据库
     * 注释解释：
     * 1. 为什么需要检查参数键名的唯一性？ 系统配置中，参数键名是唯一的标识，如果新增的参数键名已存在，将会导致数据的不一致或混淆，因此需要进行唯一性校验
     * 2. 为什么在方法上使用 @Validated 注解？ 该注解用于开启参数校验功能，确保传入的参数符合预定义的校验规则，提高数据的准确性和安全性
     *
     * @param configKey 参数Key
     * @return 操作结果，成功或失败的消息 {@link R} 是一个泛型类，表示API返回结果，这里使用 Void 类型表示没有具体的返回内容
     */
    @GetMapping(value = "/configKey/{configKey}")
    public R<String> getConfigKey(@PathVariable String configKey) {
        return R.ok("操作成功", configService.selectConfigByKey(configKey));
    }

    /**
     * 新增参数配置
     */
    @SaCheckPermission("system:config:add")
    @Log(title = "参数管理", businessType = BusinessType.INSERT)
    @PostMapping
    public R<Void> add(@Validated @RequestBody SysConfigBo config) {
        // 检查配置参数的键名是否唯一
        if (!configService.checkConfigKeyUnique(config)) {
            return R.fail("新增参数'" + config.getConfigName() + "'失败，参数键名已存在");
        }
        configService.insertConfig(config);
        return R.ok();
    }

    /**
     * 修改参数配置
     * 该方法用于修改系统配置参数，但在修改前会检查参数键名的唯一性，如果已存在相同的参数键名，则修改失败
     * 如果唯一性校验通过，将更新系统配置信息，并返回成功提示
     *
     * @param config 经过验证的系统配置信息对象
     * @return R<Void> 返回一个表示操作结果的对象，包含状态码和消息
     */
    @SaCheckPermission("system:config:edit")
    @Log(title = "参数管理", businessType = BusinessType.UPDATE)
    @PutMapping
    public R<Void> edit(@Validated @RequestBody SysConfigBo config) {
        // 检查配置键名是否唯一，如果不唯一，则返回失败提示
        if (!configService.checkConfigKeyUnique(config)) {
            return R.fail("修改参数'" + config.getConfigName() + "'失败，参数键名已存在");
        }
        // 更新系统配置信息
        configService.updateConfig(config);
        return R.ok();
    }

    /**
     * 根据参数键名修改参数配置
     *
     * @param config 包含要更新的系统配置信息的请求体
     * @return R<Void> 更新操作的结果，成功或失败的响应
     */
    @SaCheckPermission("system:config:edit")
    @Log(title = "参数管理", businessType = BusinessType.UPDATE)
    @PutMapping("/updateByKey")
    public R<Void> updateByKey(@RequestBody SysConfigBo config) {
        configService.updateConfig(config);
        return R.ok();
    }

    /**
     * 删除参数配置
     * 该方法调用configService的deleteConfigByIds方法来执行实际的删除操作，
     * 接收一个路径变量传入的Long类型数组configIds，表示需要删除的配置ID列表
     * 不需要返回具体的删除内容，只关心操作是否成功，因此返回R<Void>类型
     *
     * @param configIds 参数ID串 需要删除的配置ID数组，通过路径变量传入
     * @return 删除操作的结果，成功时返回R.ok()
     */
    @SaCheckPermission("system:config:remove")
    @Log(title = "参数管理", businessType = BusinessType.DELETE)
    @DeleteMapping("/{configIds}")
    public R<Void> remove(@PathVariable Long[] configIds) {
        configService.deleteConfigByIds(configIds);
        return R.ok();
    }

    /**
     * 刷新参数缓存
     * 该方法调用配置服务的resetConfigCache方法来重置配置缓存这在系统配置发生更改时调用，
     * 确保系统能够及时加载最新的配置信息
     *
     * @return 返回一个表示操作结果的对象，具体结果由R<Void>表示在这里，R是一个泛型类，
     *         表示操作结果，Void表示没有返回具体的值
     */
    @SaCheckPermission("system:config:remove")
    @Log(title = "参数管理", businessType = BusinessType.CLEAN)
    @DeleteMapping("/refreshCache")
    public R<Void> refreshCache() {
        configService.resetConfigCache();
        return R.ok();
    }
}
